package invite

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"shimmer/neusoft_club_backend/controllers/cons"
	"shimmer/neusoft_club_backend/dao/domain"
	"shimmer/neusoft_club_backend/middlewares/auth_middleware"
	"shimmer/neusoft_club_backend/services"
	"shimmer/neusoft_club_backend/services/club_service"
	"shimmer/neusoft_club_backend/services/errs"
	"shimmer/neusoft_club_backend/services/invite_service"
)

type inviteUserJoinClubMutation struct {
	UserID int64 `json:"user_id" form:"user_id" xml:"user_id" binding:"required"`
}
type createInviteLinkMutation struct {
	BeginTime   int64 `json:"begin_time" form:"begin_time" binding:"required"`
	EndTime     int64 `json:"end_time" form:"end_time" binding:"required"`
	InviteCount int64 `json:"invite_count" form:"invite_count" binding:"required"`
}
type createInviteLinkRes struct {
	invite_service.InviteLinkParameters
	Link domain.ClubInviteLinkDTO `json:"link"`
}

func inviteUserJoinClub(c *gin.Context) {
	user, err := domain.GetUserFromContext(c)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	clubBinding := &cons.ClubUriParamBinding{}

	if err = c.ShouldBindUri(clubBinding); err != nil {
		services.AbortWithError(c, err)
		return
	}
	inviteMutation := &inviteUserJoinClubMutation{}
	if err = c.ShouldBind(inviteMutation); err != nil {
		services.AbortWithDatabaseError(c, err)
		return
	}
	err = club_service.InviteUserJoinClub(&club_service.InviteUserJoinClubMutation{
		ClubID:     clubBinding.ClubID,
		OperatorID: user.ID,
		UserID:     inviteMutation.UserID,
	})
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	c.AbortWithStatus(http.StatusNoContent)
	return
}

// @Summary 创建邀请链接
// @Description 返回邀请链接对象和参数签名,开始时间和结束时间均为Unix时间戳，单位为秒
// @Tags 社团,邀请链接
// @Param clubID path integer true "社团ID"
// @Param value body invite.createInviteLinkMutation true "value"
// @Success 200 {object} createInviteLinkRes
// @Router /api/club/{clubID}/invite/link [post]
func createInviteLink(c *gin.Context) {
	user, err := domain.GetUserFromContext(c)
	if err != nil {
		return
	}
	clubBinding := &cons.ClubUriParamBinding{}

	if err = c.ShouldBindUri(clubBinding); err != nil {
		services.AbortWithError(c, err)
		return
	}
	owner, err := club_service.CheckIsClubOwner(user.ID, clubBinding.ClubID)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	if !owner {
		services.AbortWithError(c, errs.ErrNotClubManager)
		return
	}
	mutation := &createInviteLinkMutation{}
	if err = c.ShouldBind(mutation); err != nil {
		services.AbortWithError(c, err)
		return
	}
	param := &invite_service.InviteParameters{
		ClubID:    clubBinding.ClubID,
		BeginTime: mutation.BeginTime,
		EndTime:   mutation.EndTime,
	}
	l, s, err := invite_service.CreateInviteLink(user.ID, param)
	if err != nil {
		return
	}

	c.JSON(http.StatusOK, createInviteLinkRes{
		invite_service.InviteLinkParameters{
			InviteParameters: *param,
			Signature:        s,
		},
		*l.ToDTO(),
	})
}

// @Summary 删除邀请链接
// @Description
// @Tags 社团,邀请链接
// @Param clubID path integer true "社团ID"
// @Param inviteID path integer true "邀请ID"
// @Success 204
// @Router /api/club/{clubID}/invite/link/{inviteID} [delete]
func delInviteLink(c *gin.Context) {
	user, err := domain.GetUserFromContext(c)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	clubBinding := &cons.ClubUriParamBinding{}
	if err = c.ShouldBindUri(clubBinding); err != nil {
		services.AbortWithError(c, err)
		return
	}
	inviteBinding := &cons.InviteUriParamBinding{}
	if err = c.ShouldBindUri(inviteBinding); err != nil {
		services.AbortWithError(c, err)
		return
	}
	invite, err := invite_service.FindInviteLinkByID(inviteBinding.InviterID)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	if clubBinding.ClubID != invite.ClubID {
		isAdmin, err := club_service.CheckIsAdmin(user.ID)
		if err != nil {
			services.AbortWithError(c, err)
			return
		}
		if !isAdmin {
			services.AbortWithError(c, errs.ErrNotAdmin)
			return
		}
	}
	err = invite_service.DeleteInviteLink(inviteBinding.InviterID)
	if err != nil {
		services.AbortWithError(c, err)
		return
	}
	c.AbortWithStatus(http.StatusNoContent)
}

func ConfigureClubInviteController(r *gin.RouterGroup) {
	r.POST("/user", auth_middleware.AuthLoginMiddleware(), inviteUserJoinClub)
	r.POST("/link", auth_middleware.AuthLoginMiddleware(), createInviteLink)
	r.DELETE(fmt.Sprintf("/link/:%s", cons.InviteParam), auth_middleware.AuthLoginMiddleware(), delInviteLink)

}
